local FriendLevelingMonitor, events = CreateFrame("Frame","FriendLevelingMonitor"), {};
local MSG_PREFIX = "FLM";
local LISTSIZE = 20;
FLM_AFKTIME = 5*60; -- 5 minutes
FLM_Statuses = {"ONLINE", "OFFLINE", "INACTIVE"}
FLM_ActiveList = {}

function FriendLevelingMonitor:SendMessage(to, msg)
	SendAddonMessage(MSG_PREFIX, msg, "WHISPER", to);
end

function FriendLevelingMonitor:SendToOnlineFriends(msg)
	numberOfFriends = GetNumFriends();
	for i=1, numberOfFriends do
		local name, _, _, _, online = GetFriendInfo(i);
		if (online) then FriendLevelingMonitor:SendMessage(name, msg); end
	end	
end

function FriendLevelingMonitor:GetCurrentPercentage()
	return floor( (UnitXP("player") / UnitXPMax("player"))*100 );
end

function FriendLevelingMonitor:UpdateList(character)
	FLM_ActiveList[character.name] = {xp=character.xp, lvl=character.lvl, status=character.status, lastchanged=character.lastchanged}
end

function FriendLevelingMonitor:PrintList()
	for k, v in pairs(FLM_ActiveList) do
		local inactive = time()-v.lastchanged
		if (v.status ~= "OFFLINE" and inactive >= FLM_AFKTIME) then v.status = FLM_Statuses[3] end
		print(k.."["..v.lvl.."] is now at "..v.xp.."%. Status: "..v.status);
	end			
end
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Slash commands
SLASH_FLM1 = "/flm"
function SlashCmdList.FLM(msg, editbox)
	if msg == "list" then FriendLevelingMonitor:PrintList() end
end

-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Eventhandlers
function events:PLAYER_XP_UPDATE(...)
	if ((time() - timeLast) >= 1) then
		FriendLevelingMonitor:SendToOnlineFriends("XP "..FriendLevelingMonitor:GetCurrentPercentage().." "..UnitLevel("player"));
		timeLast = time();
	end
end

function events:PLAYER_LEVEL_UP(...)
	FriendLevelingMonitor:SendToOnlineFriends("LEVELED ".."0 "..select(1,...));
end

function events:CHAT_MSG_ADDON(...)
	local pre,msg,_,sender = ...;
	if pre == MSG_PREFIX then
		local msgtype,xp,lvl = strsplit(" ", msg, 3);
		if (msgtype == "XP" or msgtype == "ONLINE" or msgtype == "LEVELED") then
			FriendLevelingMonitor:UpdateList({name=sender,xp=xp,lvl=lvl, status=FLM_Statuses[1], lastchanged=time()});
			if (msgtype == "ONLINE") then
				FriendLevelingMonitor:SendMessage(sender, "XP "..FriendLevelingMonitor:GetCurrentPercentage().." "..UnitLevel("player"));
			elseif (msgtype == "LEVELED") then
				if (FriendLevelingMonitor_View ~= nil) then
					FriendLevelingMonitor_View:LevelUp(sender)
				end
			end			
		elseif (msgtype == "OFFLINE")then
			FriendLevelingMonitor:UpdateList({name=sender,xp=xp,lvl=lvl, status=FLM_Statuses[2], lastchanged=time()});
		end
		if (FriendLevelingMonitor_View ~= nil) then
			FriendLevelingMonitor_View:Update(sender)
		end	
	end	
end

function events:CHAT_MSG_WHISPER(...)
	local msg,sender = ...;
	local msgtype,xp,lvl = strsplit(" ", msg, 3);
	if (msgtype == "XP" or msgtype == "ONLINE" or msgtype == "LEVELED") then
		FriendLevelingMonitor:UpdateList({name=sender,xp=xp,lvl=lvl, status=FLM_Statuses[1], lastchanged=time()});
		if (msgtype == "ONLINE") then
			print(sender.." came online. Sending current data.");
		elseif (msgtype == "LEVELED") then
			if (FriendLevelingMonitor_View ~= nil) then
				FriendLevelingMonitor_View:LevelUp(sender)
			end
		end
	elseif (msgtype == "OFFLINE")then
		FriendLevelingMonitor:UpdateList({name=sender,xp=xp,lvl=lvl, status=FLM_Statuses[2], lastchanged=time()});
		print(sender.." went offline. Changing his status.");
	end
	if (FriendLevelingMonitor_View ~= nil) then
		FriendLevelingMonitor_View:Update(sender)
	end
end

function events:ADDON_LOADED(...)
	if (select(1,...) == self:GetName()) then
		print("Friend Leveling Monitor loaded");
		timeLast = time();
	end
end

function events:PLAYER_LOGIN(...)
	-- Send a message to all online friends indicating that our character just came online with current xp% and level
	-- All online friends with addon installed should answer with their respective xp% and level
	FriendLevelingMonitor:SendToOnlineFriends("ONLINE "..FriendLevelingMonitor:GetCurrentPercentage().." "..UnitLevel("player"));
end

function events:PLAYER_LEAVING_WORLD(...)
	-- Should send a message to all online friends that we are going offline
	FriendLevelingMonitor:SendToOnlineFriends("OFFLINE "..FriendLevelingMonitor:GetCurrentPercentage().." "..UnitLevel("player"));
end

FriendLevelingMonitor:SetScript("OnEvent", function(self, event, ...)
	events[event](self, ...); -- call one of the functions above
end);

for k, v in pairs(events) do
	FriendLevelingMonitor:RegisterEvent(k); -- Register all events for which handlers have been defined
end